package com.fileupload.upload.log;

import com.fileupload.common.Result;
import com.fileupload.config.ApplicationConfig;
import com.fileupload.config.MonitorConfig;
import com.fileupload.config.ServerConfig;
import com.fileupload.mapper.FileUploadLogMapper;
import com.fileupload.model.entity.FileUploadLog;
import com.fileupload.model.entity.UploadStatus;
import com.fileupload.server.ProtocolType;
import com.fileupload.utils.PathUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.io.File;
import java.net.InetAddress;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * 文件上传日志服务实现类
 *
 * @author 小乙
 */
@Service
public class FileUploadLogServiceImpl implements FileUploadLogService {
    private static final Logger logger = LoggerFactory.getLogger(FileUploadLogServiceImpl.class);

    @Autowired
    private FileUploadLogMapper uploadLogMapper;

    @Autowired
    private BatchLogCollectorService batchLogCollectorService;

    @Autowired
    private ApplicationConfig applicationConfig;

    private String deviceIdentifier;

    @PostConstruct
    public void init() {
        // 初始化设备标识
        this.deviceIdentifier = getDeviceIdentifier();

        // 根据配置决定是否初始化数据库表
        if (applicationConfig.isLogDatabaseEnabled()) {
            logger.info("日志入库功能已开启，开始初始化数据库相关功能");
            initDatabaseTable();
        } else {
            logger.info("日志入库功能已关闭，跳过数据库初始化步骤");
        }
    }

    @Override
    public void logUploadResult(File file, MonitorConfig monitorConfig, ServerConfig serverConfig,
                                long startTime, long endTime, boolean success, String errorMessage) {
        // 如果日志入库功能已关闭，直接返回
        if (!applicationConfig.isLogDatabaseEnabled()) {
            logger.debug("日志入库功能已关闭，跳过日志记录: {}", file.getName());
            return;
        }

        try {
            // 创建日志实体
            FileUploadLog log = new FileUploadLog();

            // 设置日志信息
            log.setInsertTime(System.currentTimeMillis());
            log.setDeviceIdentifier(deviceIdentifier);

            // 获取文件信息
            long fileSize = file.length();
            log.setFileSize(fileSize);
            log.setFileUnit(getFileUnit(fileSize));
            log.setFileMtime(file.lastModified() / 1000); // 转换为秒
            log.setFileCtime(file.lastModified() / 1000); // Java不直接支持ctime，使用mtime替代

            // 准备上传文件信息
            log.setUploadFileName(file.getName());
            log.setUploadFile(file.getAbsolutePath());
            log.setMonitorName(monitorConfig.getName());
            log.setMonitorDir(monitorConfig.getMonitorDir());

            // 设置服务器信息
            if (serverConfig != null) {
                log.setServerName(serverConfig.getName());
                log.setServerIp(serverConfig.getAddr().split(":")[0]);
                log.setProtocolType(ProtocolType.fromName(serverConfig.getProtocol()).getCode());

                // 构建包含archive配置的远程路径
                StringBuilder remotePathBuilder = new StringBuilder();
                String baseDir = serverConfig.getDir();
                String archive = serverConfig.getArchive();

                // 添加基础目录
                if (baseDir != null && !baseDir.isEmpty()) {
                    remotePathBuilder.append(baseDir);
                    if (!baseDir.endsWith("/")) {
                        remotePathBuilder.append("/");
                    }
                }

                // 处理归档目录
                if (archive != null && !archive.isEmpty()) {
                    if (archive.equalsIgnoreCase("date")) {
                        // 创建yyyy-MM-dd格式的日期目录
                        String dateDir = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
                        remotePathBuilder.append(dateDir).append("/");
                    } else if (archive.equalsIgnoreCase("path") && monitorConfig != null) {
                        // 实现path选项：基于文件相对于监控目录的路径创建子目录
                        String monitorDir = monitorConfig.getMonitorDir();
                        if (monitorDir != null && !monitorDir.isEmpty()) {
                            // 规范化路径并移除盘符，解决Windows环境下的路径比较问题
                            String normalizedFilePath = PathUtils.normalizePath(file.getAbsolutePath());
                            String normalizedMonitorDir = PathUtils.normalizePath(monitorDir);

                            // 移除盘符后再进行比较
                            String filePathNoDrive = PathUtils.removeDriveLetter(normalizedFilePath);
                            String monitorDirNoDrive = PathUtils.removeDriveLetter(normalizedMonitorDir);

                            // 确保监控目录以正斜杠结尾，避免部分匹配
                            if (!monitorDirNoDrive.endsWith("/")) {
                                monitorDirNoDrive = monitorDirNoDrive + "/";
                            }

                            // 使用处理后的路径进行比较
                            if (filePathNoDrive.indexOf(monitorDirNoDrive) > -1 || normalizedFilePath.indexOf(normalizedMonitorDir) > -1) {
                                // 使用规范化的路径进行处理
                                String normalizedMonitorDirWithSlash = normalizedMonitorDir;
                                // 确保monitorDir以目录分隔符结尾
                                if (!normalizedMonitorDirWithSlash.endsWith("/")) {
                                    normalizedMonitorDirWithSlash = normalizedMonitorDirWithSlash + "/";
                                }

                                // 获取相对于监控目录的路径
                                String relativePath;
                                // 优先使用移除盘符后的路径进行计算
                                if (filePathNoDrive.indexOf(monitorDirNoDrive) > -1) {
                                    relativePath = filePathNoDrive.substring(monitorDirNoDrive.length());
                                } else {
                                    // 备用方案：直接使用规范化路径
                                    relativePath = normalizedFilePath.substring(normalizedMonitorDirWithSlash.length());
                                }

                                // 移除文件名，只保留路径部分
                                int lastSlashIndex = relativePath.lastIndexOf('/');
                                int lastBackslashIndex = relativePath.lastIndexOf('\\');
                                int pathEndIndex = Math.max(lastSlashIndex, lastBackslashIndex);

                                if (pathEndIndex >= 0) {
                                    String subPath = relativePath.substring(0, pathEndIndex);

                                    // 处理路径分隔符，统一使用正斜杠
                                    subPath = subPath.replace('\\', '/');

                                    // 确保路径以正斜杠开头（避免重复斜杠）
                                    if (!subPath.startsWith("/")) {
                                        remotePathBuilder.append(subPath).append("/");
                                    } else {
                                        remotePathBuilder.append(subPath.substring(1)).append("/");
                                    }
                                }
                            }
                        }
                    } else {
                        // 创建指定名称的子目录
                        remotePathBuilder.append(archive).append("/");
                    }
                }

                // 添加文件名
                remotePathBuilder.append(file.getName());

                log.setRemotePath(remotePathBuilder.toString());
            } else {
                log.setServerName("unknown");
                log.setServerIp("unknown");
                log.setProtocolType(ProtocolType.FTP.getCode());
                log.setRemotePath("/" + file.getName());
            }

            // 设置备份路径
            log.setBackupPath(monitorConfig.getMoveTo());

            // 设置时间信息
            log.setUploadStartTime(startTime);
            log.setUploadEndTime(endTime);
            log.setUploadEndHour(new SimpleDateFormat("yyyyMMddHH").format(new Date(endTime)));

            // 设置上传结果
            log.setFailureCount(success ? 0 : 1);
            log.setSuccessFlag(success ? UploadStatus.SUCCESS.getCode() : UploadStatus.FAILURE.getCode());
            log.setErrorMessage(errorMessage);

            // 添加日志到批量收集器
            batchLogCollectorService.addLog(log);
            logger.debug("文件上传日志添加到批量收集器: {}, 结果: {}", file.getName(), success ? "成功" : "失败");

        } catch (Exception e) {
            logger.error("记录文件上传日志异常: {}", e.getMessage(), e);
        }
    }

    @Override
    public String getDeviceIdentifier() {
        try {
            InetAddress localHost = InetAddress.getLocalHost();
            String ipAddress = localHost.getHostAddress();
            String hostName = localHost.getHostName();
            return ipAddress + "/" + hostName;
        } catch (Exception e) {
            logger.error("获取设备标识异常: {}", e.getMessage());
            return "unknown_device";
        }
    }

    @Override
    public void initDatabaseTable() {
        try {
            // 数据库表的创建将由MyBatis或数据库迁移工具管理
            // 这里可以保留空实现或添加其他初始化逻辑
            logger.info("文件上传日志模块初始化成功");
        } catch (Exception e) {
            // 如果初始化失败且日志入库功能已启用，则记录错误但不阻止应用启动
            if (applicationConfig.isLogDatabaseEnabled()) {
                logger.warn("日志数据库初始化时发生异常，但将继续运行 - 错误: {}", e.getMessage());
            } else {
                logger.debug("日志入库功能已关闭，忽略数据库初始化异常 - 错误: {}", e.getMessage());
            }
        }
    }

    @Override
    public Result<List<FileUploadLog>> getLogList(Integer page, Integer size) {
        // 如果日志入库功能已关闭，直接返回空列表
        if (!applicationConfig.isLogDatabaseEnabled()) {
            logger.debug("日志入库功能已关闭，日志查询接口返回空结果");
            return Result.success(new ArrayList<>());
        }

        try {
            // 简单实现，返回空列表
            List<FileUploadLog> logs = new ArrayList<>();
            Result<List<FileUploadLog>> result = Result.success(logs);
            result.setTotal(0);
            return result;
        } catch (Exception e) {
            logger.error("获取日志列表失败: {}", e.getMessage(), e);
            return Result.error(500, "获取日志列表失败");
        }
    }

    @Override
    public Result<FileUploadLog> getLogDetail(Long id) {
        // 如果日志入库功能已关闭，直接返回null结果
        if (!applicationConfig.isLogDatabaseEnabled()) {
            logger.debug("日志入库功能已关闭，日志详情接口返回空结果");
            return Result.success(null);
        }

        try {
            // 简单实现，返回null
            return Result.success(null);
        } catch (Exception e) {
            logger.error("获取日志详情失败: {}", e.getMessage(), e);
            return Result.error(500, "获取日志详情失败");
        }
    }

    /**
     * 获取文件单位
     */
    private String getFileUnit(long fileSize) {
        if (fileSize < 1024) {
            return "B";
        } else if (fileSize < 1024 * 1024) {
            return "KB";
        } else if (fileSize < 1024 * 1024 * 1024) {
            return "MB";
        } else {
            return "GB";
        }
    }
}